interface XHRRequestConfig {
    method: string;
    url: string;
    params?: any;
    headers?: Record<string, string>;
    responseType?: string;
    dataType?: string;
    withCredentials?: boolean;
    timeout?: number;
    config?: any;
}

interface XHRResponse {
    data: any;
    status: number;
    headers: Record<string, string>;
    statusText: string;
    config: any;
}

/**
 * Make an XHR request as a fallback for other request methods
 * @param options XHR request configuration
 * @returns Promise that resolves with the response or rejects with an error
 */
export function xhrRequest(options: XHRRequestConfig): Promise<XHRResponse> {
    const {
        method,
        url,
        params = {},
        headers = {},
        responseType = 'text',
        dataType = 'json',
        withCredentials = false,
        timeout,
        config = {}
    } = options;

    return new Promise((resolve, reject) => {
        try {
            const xhr = new XMLHttpRequest();

            // Parse response headers helper function
            const parseResponseHeaders = (headerString: string): Record<string, string> => {
                const responseHeaders: Record<string, string> = {};
                if (!headerString) return responseHeaders;

                const headerPairs = headerString.split('\r\n');
                headerPairs.forEach((headerPair) => {
                    const index = headerPair.indexOf(': ');
                    if (index > 0) {
                        const key = headerPair.substring(0, index);
                        const val = headerPair.substring(index + 2);
                        responseHeaders[key] = val;
                    }
                });
                return responseHeaders;
            };

            // Process response data based on dataType
            const processResponseData = (xhr: XMLHttpRequest, dataType: string) => {
                try {
                    if (dataType === 'json' && xhr.responseText) {
                        return JSON.parse(xhr.responseText);
                    }
                    return xhr.response || xhr.responseText;
                } catch (parseError) {
                    return xhr.responseText;
                }
            };

            // Handle response
            xhr.onload = function () {
                const responseData = processResponseData(xhr, dataType);
                const headerString = xhr.getAllResponseHeaders();
                const responseHeaders = parseResponseHeaders(headerString);

                resolve({
                    data: responseData,
                    status: xhr.status,
                    headers: responseHeaders,
                    statusText: xhr.statusText,
                    config
                });
            };

            // Handle error
            xhr.onerror = function () {
                reject({
                    error: new Error('Network Error'),
                    config,
                    url,
                    message: 'XHR Network Error',
                    timestamp: new Date().toISOString()
                });
            };

            // Handle timeout
            xhr.ontimeout = function () {
                reject({
                    error: new Error('Request Timeout'),
                    config,
                    url,
                    message: 'XHR Request Timeout',
                    timestamp: new Date().toISOString()
                });
            };

            // Build URL with query parameters for GET requests
            const buildUrl = (baseUrl: string, method: string, params: any) => {
                if (method.toUpperCase() === 'GET' && params) {
                    const separator = baseUrl.includes('?') ? '&' : '?';
                    return `${baseUrl}${separator}${new URLSearchParams(params).toString()}`;
                }
                return baseUrl;
            };

            // Open request
            xhr.open(method, buildUrl(url, method, params), true);

            // Set response type
            if (responseType) {
                if (responseType === 'arraybuffer') {
                    xhr.responseType = 'arraybuffer';
                } else if (responseType === 'blob') {
                    xhr.responseType = 'blob';
                } else {
                    xhr.responseType = '';
                }
            }

            // Set credentials
            if (withCredentials) {
                xhr.withCredentials = true;
            }

            // Set headers
            if (headers) {
                Object.keys(headers).forEach((key) => {
                    xhr.setRequestHeader(key, headers[key]);
                });
            }

            // Set timeout if specified
            if (timeout) {
                xhr.timeout = timeout;
            }

            // Prepare request data based on content type and method
            const prepareRequestData = (
                method: string,
                params: any,
                headers: Record<string, string>
            ) => {
                if (method.toUpperCase() === 'GET') {
                    return null;
                }

                if (headers['Content-Type'] === 'application/json') {
                    return JSON.stringify(params);
                }

                if (
                    !(params instanceof FormData) &&
                    typeof params === 'object' &&
                    params !== null
                ) {
                    const formData = new URLSearchParams();
                    Object.keys(params).forEach((key) => {
                        formData.append(key, params[key]);
                    });
                    return formData;
                }

                return params;
            };

            // Send request
            xhr.send(prepareRequestData(method, params, headers));
        } catch (xhrError) {
            console.error(`XHR request failed: ${url}`, xhrError);
            reject({
                error: xhrError,
                config,
                url,
                message: 'XHR setup failed',
                timestamp: new Date().toISOString()
            });
        }
    });
}
